/**
 * JAVACC DEMO 1.0
 */
package com.apache.passport.controller;

import com.apache.api.manager.BaseManager;
import com.apache.api.vo.ParamsVo;
import com.apache.api.vo.ResultEntity;
import com.apache.api.vo.ResultMsg;
import com.apache.cache.util.Validator;
import com.apache.database.constant.SystemTools;
import com.apache.passport.aop.LoginAopRunable;
import com.apache.passport.aop.PassportTheardPool;
import com.apache.passport.common.DesUtils;
import com.apache.passport.common.PassPortConst;
import com.apache.passport.common.PassportHelper;
import com.apache.passport.entity.LoginInfo;
import com.apache.passport.entity.LonErrToken;
import com.apache.passport.entity.Token;
import com.apache.passport.entity.UctUser;
import com.apache.passport.jwt.CommonResponse;
import com.apache.passport.manager.UctUserManager;
import com.apache.tools.ConfigUtil;
import com.apache.tools.StrUtil;
import net.sf.json.JSONObject;
import org.owasp.esapi.ESAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Map;

/**
 * description:登录登出操作
 *
 * @author Hou Dayu 创建时间：2016-12-18
 */
@Controller
@RequestMapping({ "/passport/login/" })
public class LoginAction extends SsoBaseAction<UctUser> {

    @Autowired
    private UctUserManager uctUserManager;

    private final String LOGIN_SUCCESS = getPrefix() + "success";

    private final String LOGIN_REQUEST = getPrefix() + "request";

    private String COOKIENAME = SystemTools.getInstance().getValue("cookieName");

    @RequestMapping(value = "login", method = RequestMethod.POST)
    @ResponseBody
    public Object customLogin(HttpServletRequest request, HttpServletResponse response) {
        String userEname = request.getParameter("userName");
        String password = request.getParameter("password");
        //String referer = request.getHeader("Referer") //REFRESH
        ResultMsg rmsg = new ResultMsg("F", "用户名不存在或密码错误");
        if (Validator.isNull(userEname)) {
            rmsg.setMsg("用户名不能为空");
            return rmsg;
        }
        if (Validator.isNull(password)) {
            rmsg.setMsg("密码不能为空");
            return rmsg;
        }
        return null;
    }

    /**
     * TODO 登录.
     *
     * @see
     */
    @RequestMapping({ "login.action" })
    @ResponseBody
    public Object login(HttpServletRequest request, HttpServletResponse response, UctUser user) {
        ResultEntity result = new ResultEntity();
        //判断是否为外部系统登录
        String sysEname = request.getParameter("sys");
        String setCookieUrl = request.getParameter("cset");
        String goUrl = request.getParameter("go");
        String clientId = request.getParameter("_client");
        String tokenCookie = PassportHelper.getInstance().getCurrCookie(request);
        Token tokenc = PassPortConst.getToken(tokenCookie);
        String goOn = SystemTools.getInstance().getValue("otherGO");
        String tokenId = Validator.generate() + request.getSession().getId();
        String service_url = SystemTools.getInstance().getValue("rpc_service_url");
        ResultMsg rmsg = new ResultMsg("F", "用户名不存在或密码错误");

        //如果为没有go地址,则自动赋值,防止其他项目无法登陆
        if (Validator.isNull(goUrl)) {
            goUrl = SystemTools.getInstance().getValue("login.url");
            goUrl += SystemTools.getInstance().getValue("jump.url");
        }

        boolean flag_op = false;
        if (Validator.isNull(user.getUserEname())) {
            rmsg.setMsg("用户名不能为空");
            return rmsg;
        }
        if (Validator.isNull(user.getUserPass())) {
            rmsg.setMsg("密码不能为空");
            return rmsg;
        }
        if (Validator.isNull(sysEname)) {
            sysEname = "passport";
        }
        if (goOn.equals(sysEname)) {
            flag_op = true;
            sysEname = "移动设备或非验证系统";
        }

        LoginInfo loginInfo = getLoginInfo(request, sysEname, "", sysEname, user.getUserEname(),
                tokenId);
        ParamsVo<UctUser> vo = this.getParamsVo(request, null);

        if (!Validator.isNull(sysEname) && !Validator.isNull(setCookieUrl) && !Validator
                .isNull(goUrl) && !Validator.isNull(clientId)) {
            //2015年5月6日15:42:31
            //防止出现恶意XSS脚本攻击
            setCookieUrl = ESAPI.encoder().decodeForHTML(setCookieUrl);
            goUrl = ESAPI.encoder().decodeForHTML(goUrl);
            clientId = ESAPI.encoder().decodeForHTML(clientId);
            sysEname = ESAPI.encoder().decodeForHTML(sysEname);

            boolean csetDomain = PassportHelper.getInstance().isDomain(setCookieUrl);
            if (!csetDomain) {
                rmsg.setMsg("URL地址信息错误!");
                return rmsg;
            }

            //2015年2月2日09:16:36 增加sha1解密
            ArrayList<String> lst = new ArrayList<String>();
            lst.add(service_url);
            if (flag_op) {
                lst.add(goOn);
            } else {
                lst.add(sysEname);
            }
            lst.add(setCookieUrl);
            lst.add(goUrl);
            lst.add("apache");
            Collections.sort(lst);
            String sha1Rtn = PassportHelper.getInstance().SHA1(lst);
            if (!sha1Rtn.equals(clientId)) {
                rmsg.setFlag("F");
                rmsg.setMsg("系统检测到URL信息被篡改!");
                return rmsg;
            }

            if (!Validator.isEmpty(tokenc)) {
                rmsg.setFlag("T");
                rmsg.setMsg("跳转页面");
                return rmsg;
            } else {
                ParamsVo userStateVo = new ParamsVo();
                userStateVo.setMethodKey("userState");
                userStateVo.setParams("userEname", user.getUserEname());
                result = (ResultEntity) uctUserManager.execute(userStateVo);
                if ("F".equals(result.getEntity())) {
                    rmsg.setFlag("F");
                    rmsg.setMsg(result.getMessage());
                    return rmsg;
                }

                String remoteIp = request.getRemoteAddr();
                vo.setMethodKey("outSideLogin");
                vo.setObj(user);
                vo.setParams("loginInfo", loginInfo);
                vo.setParams("remoteIp", remoteIp);
                vo.setParams("sessionId", request.getSession().getId());
                vo.setParams("tokenId", tokenId);
                vo.setParams("userEname", user.getUserEname());
                //vo.setParams("userPass", MD5Utils.MD5(user.getUserPass()))
                //2015年1月30日16:06:45 update 去掉md5加密 前端页面 index.jsp添加md5加密
                vo.setParams("userPass", user.getUserPass());
                vo.setParams("sysEname", sysEname);
                vo.setParams("setCookieUrl", setCookieUrl);
                vo.setParams("goUrl", goUrl);
                vo.setParams("clientId", clientId);
                boolean flag = (Boolean) uctUserManager.execute(vo);
                if (flag) {
                    request.setAttribute("tokenId", tokenId);

                    if (ConfigUtil.getInstance().checkFileUpdate("") || StrUtil.isNull(COOKIENAME)) {
                        COOKIENAME = SystemTools.getInstance().getValue("cookieName");
                    }

                    Cookie cookie = new Cookie(COOKIENAME, tokenId);
                    cookie.setPath("/");
                    response.addCookie(cookie);

                    Cookie ucsso = new Cookie("_uc.sso", user.getUserEname());
                    ucsso.setPath("/");
                    response.addCookie(ucsso);

                    rmsg.setFlag("T");
                    //2015年6月8日16:40:07 修改| 替换
                    goUrl = goUrl.replace("|", "&");
                    savelogInfo(loginInfo);
                    rmsg.setMsg(goUrl);
                    return rmsg;
                } else {
                    rmsg = checkErrorToken(remoteIp, user, rmsg, request);
                }
            }
        } else {

            ParamsVo userStateVo = new ParamsVo();
            userStateVo.setMethodKey("userState");
            userStateVo.setParams("userEname", user.getUserEname());
            result = (ResultEntity) uctUserManager.execute(userStateVo);
            if ("F".equals(result.getEntity())) {
                rmsg.setFlag("F");
                rmsg.setMsg(result.getMessage());
                return rmsg;
            }

            String remoteIp = request.getRemoteAddr();
            //非外部系统连接登录
            vo.setMethodKey("login");
            vo.setObj(user);

            vo.setParams("loginInfo", loginInfo);
            vo.setParams("remoteIp", remoteIp);
            vo.setParams("sessionId", request.getSession().getId());
            vo.setParams("tokenId", tokenId);
            vo.setParams("userEname", user.getUserEname());
            //vo.setParams("userPass", MD5Utils.MD5(user.getUserPass()))
            //2015年1月30日16:06:45 update 去掉md5加密 前端页面 index.jsp添加md5加密
            vo.setParams("userPass", user.getUserPass());
            boolean flag = (Boolean) uctUserManager.execute(vo);
            if (flag) {
                rmsg.setFlag("T");
                //2015年6月8日16:40:07 修改| 替换
                goUrl = goUrl.replace("|", "&");
                rmsg.setMsg(goUrl);
                if (ConfigUtil.getInstance().checkFileUpdate("") || StrUtil.isNull(COOKIENAME)) {
                    COOKIENAME = SystemTools.getInstance().getValue("cookieName");
                }
                Cookie cookie = new Cookie(COOKIENAME, tokenId);
                cookie.setPath("/");
                response.addCookie(cookie);

                Cookie ucsso = new Cookie("_uc.sso", user.getUserEname());
                ucsso.setPath("/");
                response.addCookie(ucsso);

                request.getSession().setAttribute("goUrl", "/");
                savelogInfo(loginInfo);
                return rmsg;
            } else {
                rmsg = checkErrorToken(remoteIp, user, rmsg, request);
            }
        }

        return rmsg;
    }

    /**
     * TODO 登录.
     */
    @RequestMapping({ "login" })
    @ResponseBody
    public Object loginJwt(HttpServletRequest request, HttpServletResponse response, UctUser user) {
        ResultEntity result = new ResultEntity();
        //判断是否为外部系统登录
        String goUrl = Validator
                .getDefaultStr(request.getParameter("go"), request.getParameter("redirect_uri"));
        String orgEname = request.getParameter("orgEname");
        String tokenId = Validator.generate() + request.getSession().getId();
        ResultMsg rmsg = new ResultMsg("F", "用户名不存在或密码错误");
        String clientid = StrUtil
                .doNull(request.getParameter("clientid"), request.getParameter("sys"));
        //如果为没有go地址,则自动赋值,防止其他项目无法登陆
        boolean ifInner = true;
        if (Validator.isNull(goUrl)) {
            String referer = request.getHeader("Referer");
            String loginUrl = SystemTools.getInstance().getValue("login.url");
            if (referer.indexOf(loginUrl) != -1) {
                goUrl = SystemTools.getInstance().getValue("login.url");
                goUrl += SystemTools.getInstance().getValue("jump.url");
            } else {
                goUrl = referer;
                ifInner = false;
            }
        } else {
            ifInner = false;
        }
        if ("T".equalsIgnoreCase(StrUtil.doNull(SystemTools.getInstance().getValue("is_rand_code"),
                "F"))) {//启用验证码，验证验证码
            String randCode = String.valueOf(request.getSession().getAttribute("randCode"));
            if ((StrUtil.isNull(request.getParameter("rand")))) {
                rmsg = new ResultMsg("F", "验证码不能为空");
                return rmsg;
            }
            if (!request.getParameter("rand").equals(randCode)) {
                rmsg = new ResultMsg("F", "验证码错误");
                return rmsg;
            }
        }
        if (Validator.isNull(user.getUserEname())) {
            rmsg.setMsg("用户名不能为空");
            return rmsg;
        }
        if (Validator.isNull(user.getUserPass())) {
            rmsg.setMsg("密码不能为空");
            return rmsg;
        }

        LoginInfo loginInfo = getLoginInfo(request, goUrl, "", StrUtil.doNull(clientid, "passport"),
                user.getUserEname(), tokenId);
        ParamsVo<UctUser> vo = new ParamsVo<UctUser>();

        vo.setMethodKey("userState");
        vo.setParams("userEname", user.getUserEname());
        result = (ResultEntity) uctUserManager.execute(vo);
        if ("F".equals(result.getEntity())) {
            rmsg.setFlag("F");
            rmsg.setMsg(result.getMessage());
            return rmsg;
        }
        String goOn = SystemTools.getInstance().getValue("otherGO");
        vo = this.getParamsVo(request, null);
        String remoteIp = request.getRemoteAddr();
        vo.setMethodKey("jwtLogin");
        vo.setObj(user);
        vo.setParams("loginInfo", loginInfo);
        vo.setParams("remoteIp", remoteIp);
        vo.setParams("userEname", user.getUserEname());
        vo.setParams("orgEname", orgEname);
        vo.setParams("userPass", user.getUserPass());

        String responseType = StrUtil.doNull(request.getParameter("response_type"), "code");
        String scope = request.getParameter("scope");
        vo.setParams("clientid", ifInner ? goOn : clientid);
        vo.setParams("responseType", responseType);
        vo.setParams("scope", scope);
        ResultEntity entity = (ResultEntity) uctUserManager.execute(vo);
        CommonResponse crs = (CommonResponse) entity.getEntity();
        if (null != crs && 1000 == crs.getCode().intValue()) {
            JSONObject jo = JSONObject.fromObject(crs.getData().toString());
            String code = jo.getString("code");
            request.setAttribute("tokenId", "uni_" + code);
            Cookie cookie = new Cookie(COOKIENAME, "uni_" + code);
            cookie.setPath("/");
            response.addCookie(cookie);
            rmsg.setFlag("T");
            if (!ifInner) {
                // 修改| 替换
                goUrl = goUrl.replace("|", "&");
                loginInfo.setTokenId(jo.getString("token"));
                savelogInfo(loginInfo);
                if (goUrl.indexOf("?") == -1) {
                    goUrl += "?" + responseType + "=" + code;
                } else {
                    goUrl += "&" + responseType + "=" + code;
                }
            }
            rmsg.setMsg(goUrl);
            return rmsg;
        } else {
            rmsg = checkErrorToken(remoteIp, user, rmsg, request);
        }
        return rmsg;
    }

    private ResultMsg checkErrorToken(String remoteIp, UctUser user, ResultMsg rmsg,
            HttpServletRequest request) {
        //插件中存了错误次数,则在此判断
        LonErrToken token = PassPortConst.getLonErrToken(remoteIp, user.getUserEname());
        if (!Validator.isEmpty(token)) {
            String errCount = token.getLoginCount();
            String mim = token.getMim();
            int count = Integer.parseInt(errCount);
            String[] params = { mim };
            if (3 == count) {
                rmsg.setMsg(PassportHelper.getInstance()
                        .getMessage(request, "login_err_3", params, ""));
            } else if (6 == count) {
                rmsg.setMsg(PassportHelper.getInstance()
                        .getMessage(request, "login_err_6", params, ""));
            } else if (9 == count) {
                rmsg.setMsg(PassportHelper.getInstance()
                        .getMessage(request, "login_err_9", params, ""));
            } else if (12 == count) {
                rmsg.setMsg(PassportHelper.getInstance()
                        .getMessage(request, "login_err_12", params, ""));
            }
        }
        return rmsg;
    }

    @RequestMapping("/outside.action")
    public String mode(HttpServletRequest request) throws Exception {
        String goUrl = request.getParameter("go");
        return "redirect:" + goUrl;
    }

    /**
     * description: 封装信息对象
     *
     * @param request
     * @param lastSysEname 最后登录系统
     * @param lastSysTime 最后登录系统时间
     * @param sysEname 当前登录系统名称
     * @param userEname 当前登录人
     * @return
     */
    private LoginInfo getLoginInfo(HttpServletRequest request, String lastSysEname,
            String lastSysTime, String sysEname, String userEname, String tokenId) {
        String lgnLastipaddress = PassportHelper.getInstance().getIpAddr(request);
        String header = request.getHeader("User-agent");
        String lgnLastdevice = "";
        if (!Validator.isNull(header)) {
            int beginIndex = header.indexOf('(') + 1;
            int endIndex = header.indexOf(')');
            lgnLastdevice = header.substring(beginIndex, endIndex);
        }
        LoginInfo loginInfo = new LoginInfo();

        loginInfo.setTokenId(tokenId);
        loginInfo.setSessionId(request.getSession().getId());
        loginInfo.setSysEname(sysEname);//当前登录系统
        loginInfo.setUserEname(userEname);//当前登录人
        if (lgnLastdevice.contains("iPhone") || lgnLastdevice.contains("iPad") || lgnLastdevice
                .contains("iPad") || lgnLastdevice.contains("iTouch") || lgnLastdevice
                .contains("Mac")) {
            loginInfo.setLgnJudge("Apple");//品牌
        } else if (lgnLastdevice.contains("Android")) {
            loginInfo.setLgnJudge("Android");//品牌
        } else if (lgnLastdevice.contains("SymbianOS")) {
            loginInfo.setLgnJudge("SymbianOS");//品牌
        } else if (lgnLastdevice.contains("Windows")) {
            loginInfo.setLgnJudge("Windows");//品牌
        } else {
            loginInfo.setLgnJudge("未知品牌");//品牌
        }
        loginInfo.setLgnLastarea("未知地域");//地域
        loginInfo.setLgnLastdevice(lgnLastdevice);//介质
        loginInfo.setLgnLastipaddress(lgnLastipaddress);//ip地址
        if (Validator.isNull(lastSysEname)) {
            lastSysEname = "未知系统";
        }
        loginInfo.setLgnLastsys(lastSysEname);//最后登录系统
        if (Validator.isNull(lastSysTime)) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            lastSysTime = sdf.format(new Date());
        }
        loginInfo.setLgnLasttime(lastSysTime);//最后登录时间
        return loginInfo;
    }

    /**
     * description:  跳转至登录成功界面
     *
     * @param request
     * @return
     */
    @RequestMapping({ "login-success.action" })
    public ModelAndView initList(HttpServletRequest request) {
        ModelAndView view = new ModelAndView(LOGIN_SUCCESS);

        return view;
    }

    @RequestMapping({ "login-success" })
    public String loginSuccess(HttpServletRequest request, HttpServletResponse response,
            Map<String, Object> data) throws ServletException, IOException {
        String currCookie = PassportHelper.getInstance().getCurrCookie(request);
        if (Validator.isNull(currCookie)) {
            String jumpUrl = SystemTools.getInstance().getValue("jump.url");
            request.getRequestDispatcher(jumpUrl).forward(request, response);
            return "";
        }
        Token token = PassPortConst.getToken(currCookie);
        String consoleUser = SystemTools.getInstance().getValue("console.user");
        String desEname = token.getUserEname();
        if (!StrUtil.isNull(desEname)) {
            desEname = DesUtils.getInstance().decrypt(desEname);
            data.put("isSysAdmin", "T");
            request.getSession().setAttribute("userEname", desEname);
        }
        return LOGIN_SUCCESS;
    }

    /**
     * description:  跳转成定向
     *
     * @param request
     * @return
     */
    @RequestMapping({ "login-request.action" })
    public ModelAndView request(HttpServletRequest request) {
        ModelAndView view = new ModelAndView(LOGIN_REQUEST);
        return view;
    }

    private void savelogInfo(LoginInfo log) {
        LoginAopRunable runnable = new LoginAopRunable(log, "login");
        PassportTheardPool.getInstance().saveLogger(runnable);
    }

    @Override
    protected BaseManager<UctUser> getBaseManager() {

        return null;
    }

    @Override
    protected String getPrefix() {
        return "/passport/passport-";//passport-success.jsp
    }

    @Override
    protected Object data(HttpServletRequest httpservletrequest, String s, String s1) {

        return null;
    }

}
